#include "precom.h"
#include "BaseWindow.h"

#define TOOLTIPSIZE 255

const TCHAR* BaseWindow::CLASS_NAME = L"JurkowskimWindow";
const TCHAR* BaseWindow::CLASS_DEBUG_NAME = L"JurkowskimWindowDebug";
const TCHAR* BaseWindow::MSG_NAME = L"MsgJurkowskimWindow";

BaseWindow* single = NULL;

void BaseWindow::CreateWndClass(HICON hIcon) {
	WNDCLASS wcx, wcxd;
	
	wcx.style = CS_DBLCLKS;
	wcx.cbClsExtra = 0;
	wcx.cbWndExtra = 0;
	wcx.hInstance = hInst;
	wcx.hIcon = hIcon;
	wcx.hCursor = LoadCursor(0, IDC_ARROW);
	wcx.hbrBackground = 0;
	wcx.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
	wcx.lpszClassName = CLASS_NAME;
	wcx.lpfnWndProc = &WndProc;
	
	wcxd = wcx;
	wcxd.lpszMenuName = NULL;
	wcxd.lpszClassName = CLASS_DEBUG_NAME;
	wcxd.lpfnWndProc = &WndProcD;

	RegisterClass(&wcx);
	RegisterClass(&wcxd);
}

void BaseWindow::CreateToolbar()
{
	int bmpi;
	hToolBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLBARBMP));
	ZeroMemory(tbb, sizeof(tbb));
	bmpi = 0;
	for(int i=0; i<_TOOLSCOUNT; ++i)
	{
		tbb[i].idCommand = bmpi;
		tbb[i].iBitmap = bmpi;
		tbb[i].iString = IDS_TOOLBAR_DEBUGRES;
		tbb[i].fsState = TBSTATE_ENABLED;// | TBSTATE_WRAP ;
		tbb[i].fsStyle = TBSTYLE_BUTTON;// | BTNS_SHOWTEXT;
		if(i != 2 && i != 9 && i != 12 
			&& i != 16 && i != 20 && i != 24 && i!=28)
			++bmpi;
	}
	tbb[2].fsStyle = TBSTYLE_SEP;
	tbb[9].fsStyle = TBSTYLE_SEP;
	tbb[12].fsStyle = TBSTYLE_SEP;
	tbb[16].fsStyle = TBSTYLE_SEP;
	tbb[20].fsStyle = TBSTYLE_SEP;
	tbb[24].fsStyle = TBSTYLE_SEP;
	tbb[28].fsStyle = TBSTYLE_SEP;

	hTools = CreateToolbarEx(hWnd, 
		WS_CHILD|WS_VISIBLE|WS_BORDER| TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS,
		IDT_TOOLBAR, _TOOLSCOUNT-_TOOLSEP, NULL, (UINT_PTR)hToolBmp, 
		tbb, _TOOLSCOUNT, 24, 24, 24, 24, sizeof(TBBUTTON) );

	SendMessage(hTools, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
}

DWORD BaseWindow::GetWindowStyle() {
	if(fullScreen)
		return WS_POPUP | WS_SYSMENU | WS_VISIBLE;
	else 
		return (WS_OVERLAPPEDWINDOW | WS_VISIBLE);
}

void BaseWindow::CreateWnd() {
	DWORD style = GetWindowStyle();
	RECT rc = {0, 0, wndWidth, wndHeight};
	AdjustWindowRect(&rc, style, true);	

	hWnd = CreateWindow(/*WS_EX_COMPOSITED, */CLASS_NAME,
				L"FollowUpProgramming", style, 20, 
				20, rc.right - rc.left, 
				rc.bottom - rc.top, 0, 0, hInst, 0);

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);	
    SetFocus(hWnd);

	style = WS_POPUP | WS_CAPTION;
	RECT rcD = {0, 0, 500, 500};
	AdjustWindowRect(&rcD, style, true);	
	GetWindowRect(hWnd, &rc);
	hWndD = CreateWindow(CLASS_DEBUG_NAME,
				L"FollowUpDebug", 
				style, rc.right - 90, rc.top + 140,
				rcD.right - rcD.left, rcD.bottom - rcD.top,
				hWnd, 0, hInst, 0);
	UpdateWindow(hWndD);
	ShowWindow(hWndD, SW_SHOW);

	CreateToolbar();
    OnInit(hWnd, hDC, hRC, 1);
	OnInit(hWndD, hDCD, hRCD, 0);	
}

int BaseWindow::Run() {
	MSG msg; 
	msg.message = WM_NULL;
    
	while(msg.message != WM_QUIT) {
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
			//if (!IsDialogMessage(hWnd, &msg)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			//}
		} //else {
			//if(this->activate) {
                Update();
				Draw();
				SwapBuffers(hDC);
			//}
		//}
	}
	return static_cast<int> (msg.wParam);
}

void CALLBACK BaseWindow::TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
	//return single->OnTimer(hwnd, uMsg, idEvent, dwTime);
	single->OnTimerMethod();
}

LRESULT CALLBACK BaseWindow::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	return single->OnWndProc(hWnd, msg, wParam, lParam);
}

LRESULT CALLBACK BaseWindow::WndProcD(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	return single->OnWndProcD(hWnd, msg, wParam, lParam);
}

LRESULT BaseWindow::OnWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	POINT pp;
	LPTOOLTIPTEXT lpttt;
	LPNMHDR pnmh;
	wchar_t tip[TOOLTIPSIZE];

	switch(msg) {
	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
 		OnKeyDown(wParam);
		break;
	case WM_KEYUP:
	case WM_SYSKEYUP:
		OnKeyUp(wParam);
		break;
	case WM_LBUTTONDOWN:
		point = MAKEPOINTS(lParam);
		OnLButtonDown(wParam, lParam);
		break;
	case WM_NOTIFY:
		pnmh = (LPNMHDR)lParam;
		if(pnmh->code == TTN_GETDISPINFO)
		{
			lpttt = (LPTOOLTIPTEXT)lParam; 
			lpttt->hinst = hInst;
			LoadString (hInst, lpttt->hdr.idFrom + IDS_TOOLBAR_OPEN,    // string ID == cmd ID + 111
				tip, TOOLTIPSIZE);
			lpttt->lpszText = tip;
	    }
		break;
	case WM_COMMAND:
		if((HWND)lParam == hTools)
			OnToolbarChoosed(wParam);
		OnMenuChoosed(wParam);
		break;
	case WM_RBUTTONDOWN:	
		point = MAKEPOINTS(lParam);
		if((wParam & MK_CONTROL) == 0)
			OnRButtonDown(wParam, lParam);
		break;
	case WM_MOUSEWHEEL:		
		OnMouseWheel(wParam, lParam);
		break;
	case WM_RBUTTONUP:
		OnRButtonUp(wParam, lParam);
		break;
	case WM_LBUTTONUP:		
		OnLButtonUp(wParam, lParam);
		break;
	case WM_MOUSEMOVE:
		if( ((wParam & MK_CONTROL) != 0) && ((wParam & MK_RBUTTON) != 0) ) {
			pp.x = LOWORD(lParam);
			pp.y = HIWORD(lParam);
			ClientToScreen(hWnd, &pp);
			SetWindowPos(hWnd, HWND_TOPMOST, pp.x - point.x , pp.y - point.y , 0, 0, SWP_NOSIZE);
		}		
		OnMouseMove(wParam, lParam);
		break;
	case WM_SYSCOMMAND:
		switch (wParam)
		{
			case SC_SCREENSAVE:
			case SC_MONITORPOWER:
			return 0;
		}
		break;
	case WM_ACTIVATE:
		if (!HIWORD(wParam))
			this->activate = true;			
		else
			this->activate = false;
		return 0;
	case WM_ERASEBKGND:
		break;
	case WM_PAINT:
		//Draw();
		break;
	case WM_ENTERSIZEMOVE:
		return 0;
		break;
	case WM_CREATE:
		break;
	//case WM_WINDOWPOSCHANGED:
	//case WM_EXITSIZEMOVE:
	case WM_SIZE:
		ResizeWindow();
		SizeChanged();		
		break;
	case WM_DESTROY:
        OnWmCreate();
		OnDestroy();
		PostQuitMessage(0);
		break;
	default:
		break;
	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}

LRESULT BaseWindow::OnWndProcD(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	switch(msg) {
	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
 		OnDebugKeyDown(wParam);
		break;
	/*case WM_ACTIVATE:
		if (!HIWORD(wParam))
			this->activateDebug = true;			
		else
			this->activateDebug = false;
		return 0;*/
	case WM_ERASEBKGND:
		break;
	case WM_PAINT:
		DebugDraw();
		break;
	case WM_ENTERSIZEMOVE:
		return 0;
		break;
	case WM_CREATE:
		break;
	case WM_DESTROY:
        OnWmDebugCreate();
		OnDebugDestroy();
		break;
	default:
		break;
	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}

void BaseWindow::ResizeWindow() {
	RECT rc;
	GetClientRect(hWnd, &rc);
	wndWidth = static_cast<UINT>(rc.right - rc.left);
	wndHeight = static_cast<UINT>(rc.bottom - rc.top);
}

BaseWindow::BaseWindow(HINSTANCE hInst) {

	if(single == NULL)
		single = this;

	this->activate = true;
	this->fullScreen = false;
	this->wndHeight = 600;
	this->wndWidth = 820;
	this->toolHeight = 0;
	this->hInst = hInst;
	this->hWnd = NULL;
	this->hDC = NULL;
	this->hRC = NULL;
	this->hTools = NULL;
	this->hToolBmp = NULL;    
}

BaseWindow::~BaseWindow() {
	if(hTools)
		DestroyWindow(hTools);
	hTools = 0;
	if(hToolBmp)
		DeleteObject(hToolBmp);
	hToolBmp = 0;
	if(!UnregisterClass(CLASS_DEBUG_NAME, hInst)) {
		MessageBox(NULL, L"Could Not Unregister Debug Class.",
			L"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);		
	}
	if(!UnregisterClass(CLASS_NAME, hInst)) {
		MessageBox(NULL, L"Could Not Unregister Class.",
			L"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hInst=NULL;				
	}
}

int BaseWindow::Go(HICON hicon) {
	InitCommonControls();
	
	this->CreateWndClass(hicon);
	this->CreateWnd();
	this->OnCreate();
	return this->Run();
}

void BaseWindow::Exit() {
	PostMessage(hWnd, WM_CLOSE, 0, 0);
}